﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using System.Drawing;
using System.Drawing.Imaging;

using LowLevelGraphics.ColorSpaces;
using LowLevelGraphics.Histograms;

namespace LowLevelGraphics
{
    /// <summary>
    /// RGB Channel enumeration
    /// </summary>
    public enum RGB
    {
        R = 0,
        G = 1,
        B = 2
    }

    /// <summary>
    /// 
    /// </summary>
    public class ColorFunctions
    {
        /// <summary>
        /// Gets the RGB from char.
        /// </summary>
        /// <param name="chChar">The ch char.</param>
        /// <returns></returns>
        public static RGB GetRGBFromChar(char chChar)
        {
            return (RGB)Enum.Parse(typeof(RGB), chChar.ToString());
        }

        /// <summary>
        /// Gets the color constancy.
        /// </summary>
        /// <param name="_color">The _color.</param>
        /// <param name="_dTheta">The _d theta.</param>
        /// <returns></returns>
        public static double GetColorConstancy(Color _color, double _dTheta)
        {
            double dConstancy = Math.Cos(_dTheta) * Math.Log((double)_color.R / (double)_color.G) + Math.Sin(_dTheta) * Math.Log((double)_color.B / (double)_color.G);
            return dConstancy;
        }

        /// <summary>
        /// Gets the name of the known color by.
        /// </summary>
        /// <param name="_sName">Name of the _s.</param>
        /// <returns></returns>
        public static KnownColor GetKnownColorByName(string _sName)
        {
            KnownColor kc = (KnownColor)Enum.Parse(typeof(KnownColor), _sName, true);
            return kc;
        }

        /// <summary>
        /// Get the known color component from a Color.
        /// </summary>
        /// <param name="_color">The _color.</param>
        /// <returns></returns>
        public static Color FromKnownColorComponent(Color _color)
        {
            return Color.FromArgb(_color.R, _color.G, _color.B);
        }

        /// <summary>
        /// Froms the known color.
        /// </summary>
        /// <param name="_color">The _color.</param>
        /// <returns></returns>
        public static Color FromKnownColor(KnownColor _color)
        {
            return Color.FromKnownColor(_color);
        }

        /// <summary>
        /// Gets the color constancy2.
        /// </summary>
        /// <param name="_color">The _color.</param>
        /// <param name="_dTheta">The _d theta.</param>
        /// <returns></returns>
        public static double GetColorConstancy2(Color _color, double _dTheta)
        {
            double dConstancy = Math.Cos(_dTheta) * Math.Log((double)(_color.R + 1) / (double)(_color.G + 1)) + Math.Sin(_dTheta) * Math.Log((double)(_color.B + 1) / (double)(_color.G + 1));
            return dConstancy;
        }

        /// <summary>
        /// Creates the color map.
        /// </summary>
        /// <returns></returns>
        public ColorMap[] CreateColorMap()
        {
            ColorMap[] aColorMap = new ColorMap[256];
            for (int i = 0; i < aColorMap.Length; i++)
            {
                aColorMap[i] = new ColorMap();

                // Alte Farbe:
                Color oldColor = Color.FromArgb(i, i, i);
                aColorMap[i].OldColor = oldColor;

                // Neue Farbe [-1,1]:
                double dRed = Math.Sin(i * 2 * Math.PI / 255d - Math.PI);
                double dGreen = Math.Sin(i * 2 * Math.PI / 255d - Math.PI / 2);
                double dBlue = Math.Sin(i * 2 * Math.PI / 255d);

                // Neue Farbe [0,255]:
                dRed = (dRed + 1) * 0.5 * 255;
                dGreen = (dGreen + 1) * 0.5 * 255;
                dBlue = (dBlue + 1) * 0.5 * 255;

                Color newColor = Color.FromArgb(
                    (int)dRed,
                    (int)dGreen,
                    (int)dBlue);
                aColorMap[i].NewColor = newColor;
            }

            return aColorMap;
        }

        /// <summary>
        /// Gets the harmonic mean color value.
        /// </summary>
        /// <param name="_aColor">Color of the _a.</param>
        /// <param name="_bClip">if set to <c>true</c> [_b clip].</param>
        /// <param name="_nFactor">The _n factor.</param>
        /// <param name="_nOffset">The _n offset.</param>
        /// <returns></returns>
        private Color GetHarmonicMeanColorValue(List<Color> _aColor, bool _bClip, int _nFactor, int _nOffset)
        {
            double dValue = 1;
            double dR = 0;
            double dG = 0;
            double dB = 0;
            foreach (Color color in _aColor)
            {
                if (color.R != 0) dR += 1.0f / color.R;
                if (color.G != 0) dG += 1.0f / color.G;
                if (color.B != 0) dB += 1.0f / color.B;
            }

            double dCount = (double)_aColor.Count;
            if (dR != 0.0f) dR = dCount / dR;
            if (dG != 0.0f) dG = dCount / dG;
            if (dB != 0.0f) dB = dCount / dB;

            int nR = (int)dR * _nFactor + _nOffset;
            int nG = (int)dG * _nFactor + _nOffset;
            int nB = (int)dB * _nFactor + _nOffset;

            if (_bClip)
            {
                if (nR < 0) nR = 0;
                if (nG < 0) nG = 0;
                if (nB < 0) nB = 0;
                if (nR > 255) nR = 255;
                if (nG > 255) nG = 255;
                if (nB > 255) nB = 255;
            }
            else
            {
                nR %= 255;
                nG %= 255;
                nB %= 255;
            }
            return Color.FromArgb(nR, nG, nB);
        }

        /// <summary>
        /// Toes the int RGB.
        /// </summary>
        /// <param name="r">The r.</param>
        /// <param name="g">The g.</param>
        /// <param name="b">The b.</param>
        /// <returns></returns>
        public static int ToIntRGB(byte r, byte g, byte b)
        {
            return ToIntRGB(Color.FromArgb(r, g, b));
        }

        /// <summary>
        /// Converts the given color to the corresponding int value. No a channel considered.
        /// </summary>
        /// <param name="_color"></param>
        /// <returns></returns>
        public static int ToIntRGB(Color _color)
        {
            return (_color.R << 16) + (_color.G << 8) + _color.B;
        }

        /// <summary>
        /// Tests if the picture is grayscale,
        /// if the palette entry is empty, each pixel has to be checked.
        /// </summary>
        /// <param name="_bmp">The _BMP.</param>
        /// <returns>
        /// 	<c>true</c> if [is grayscale bitmap] [the specified _BMP]; otherwise, <c>false</c>.
        /// </returns>
        public static bool IsGrayscaleBitmap(Bitmap _bmp)
        {
            ColorPalette colorPalette = _bmp.Palette;
            bool bIsGray = true;
            if (colorPalette.Entries != null && colorPalette.Entries.Length > 0)
            {
                foreach (Color color in colorPalette.Entries)
                {
                    bIsGray &= IsGrayColor(color);
                }
            }
            else
            {
                UnsafeBitmap bmp = new UnsafeBitmap(_bmp);
                HashSet<Color> aColor = new HashSet<Color>();
                for (int y = 0; y < bmp.Height; y++)
                {
                    for (int x = 0; x < bmp.Width; x++)
                    {
                        Color color = bmp.GetPixel(x, y);
                        if (ColorFunctions.IsGrayColor(color))
                        {
                            aColor.Add(color);
                        }
                        else
                        {
                            bIsGray = false;                            
                            break;
                        }
                    }
                    if (!bIsGray)
                        break;
                }
                bmp.Dispose();
            }
            return bIsGray;
        }

        /// <summary>
        /// Checks if the color is a gray color
        /// </summary>
        /// <param name="_color"></param>
        /// <returns></returns>
        public static bool IsGrayColor(Color _color)
        {
            return _color.R == _color.G && _color.G == _color.B;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="_bitmap"></param>
        /// <returns></returns>
        public static HashSet<Color> ColorHashset(Bitmap _bitmap)
        {
            HashSet<Color> aColor = new HashSet<Color>();
            ColorPalette colorPalette = _bitmap.Palette;
            bool bIsGray = true;
            foreach (Color color in colorPalette.Entries)
            {
                aColor.Add(color);
            }
            return aColor;
        }

        /// <summary>
        /// Gets the the nearest left color.
        /// </summary>
        /// <param name="c">The c.</param>
        /// <returns></returns>
        public static Color GetNearestLeftColor(Color c)
        {
            if ((c.R <= c.G) & (c.R <= c.B))
            {
                return Color.FromArgb(0, c.G, c.B);
            }
            if ((c.G <= c.R) & (c.G <= c.B))
            {
                return Color.FromArgb(c.R, 0, c.B);
            }
            if ((c.B <= c.G) & (c.B <= c.R))
            {
                return Color.FromArgb(c.R, c.G, 0);
            }
            return c;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="c"></param>
        /// <returns></returns>
        public static Color GetNearestRightColor(Color c)
        {
            if ((c.R >= c.G) & (c.R >= c.B))
            {
                return Color.FromArgb(255, c.G, c.B);
            }
            if ((c.G >= c.R) & (c.G >= c.B))
            {
                return Color.FromArgb(c.R, 255, c.B);
            }
            if ((c.B >= c.G) & (c.B >= c.R))
            {
                return Color.FromArgb(c.R, c.G, 255);
            }
            return c;
        }

        /// <summary>
        /// Tests if the Bitmap only contains two Colors
        /// </summary>
        /// <param name="_bitmap"></param>
        /// <returns></returns>
        public static bool IsBitonal(Bitmap _bitmap)
        {
            HashSet<Color> aColor = ColorHashset(_bitmap);
            return aColor.Count == 2;
        }

        /// <summary>
        /// Tests if the Bitmap only contains three colors
        /// </summary>
        /// <param name="_bitmap"></param>
        /// <returns></returns>
        public static bool IsTriTonal(Bitmap _bitmap)
        {
            HashSet<Color> aColor = ColorHashset(_bitmap);
            return aColor.Count == 3;
        }

        /// <summary>
        /// Determines whether [is tri tonal] [the specified _bitmap].
        /// </summary>
        /// <param name="_bitmap">The _bitmap.</param>
        /// <returns>
        /// 	<c>true</c> if [is tri tonal] [the specified _bitmap]; otherwise, <c>false</c>.
        /// </returns>
        public static bool IsTriTonal(UnsafeBitmap _bitmap)
        {
            return new Statistics(_bitmap).Count == 3;
        }

        /// <summary>
        /// This will return the dominant color, i.e.
        /// the color that appears most.
        /// </summary>
        /// <param name="_bmp"></param>
        /// <returns></returns>
        public static Color GetDominantColor(UnsafeBitmap _bmp)
        {
            return GetDominantColor(_bmp, PROCESSING_MODE.ColorCount);
        }

        /// <summary>
        /// This will return the dominant color, i.e.
        /// the color that appears most dependant on the processing mode.
        /// </summary>
        /// <param name="_bmp">The _BMP.</param>
        /// <param name="_processingMode">The _processing mode.</param>
        /// <returns></returns>
        public static Color GetDominantColor(UnsafeBitmap _bmp, PROCESSING_MODE _processingMode)
        {
            Statistics a = new Statistics(_bmp);
            a.SortBy(_processingMode);
            return a[0].Color;
        }


        /// <summary>
        /// Gets the average Color of a bitmap
        /// </summary>
        /// <param name="_bmp"></param>
        /// <returns></returns>
        public static Color GetAverageColor(UnsafeBitmap _bmp)
        {
            UnsafeBitmap bmp = _bmp;
            //Used for tally
            int r = 0;
            int g = 0;
            int b = 0;

            int total = 0;

            for (int x = 0; x < bmp.Width; x++)
            {
                for (int y = 0; y < bmp.Height; y++)
                {
                    Color clr = bmp.GetPixel(x, y);

                    r += clr.R;
                    g += clr.G;
                    b += clr.B;

                    total++;
                }
            }

            //Calculate average
            r /= total;
            g /= total;
            b /= total;

            return Color.FromArgb(r, g, b);
        }

        /// <summary>
        /// Shifts the bits of the color to the left
        /// </summary>
        /// <param name="color"></param>
        /// <param name="nBits"></param>
        /// <returns></returns>
        public static Color ShiftColorLeft(Color color, int nBits)
        {
            return Color.FromArgb(color.ToArgb() << nBits);
        }

        /// <summary>
        /// Inverts a byte
        /// </summary>
        /// <param name="b"></param>
        /// <returns></returns>
        public static byte Invert(byte b)
        {
            return (byte)(255 - b);
        }

        /// <summary>
        /// Inverts this color
        /// </summary>
        /// <param name="color"></param>
        /// <returns></returns>
        public static Color Invert(Color color)
        {
            return Color.FromArgb(255 - color.R, 255 - color.G, 255 - color.B);
        }

        /// <summary>
        /// Log operation for all channels
        /// </summary>
        /// <param name="_color"></param>
        /// <param name="_dLog"></param>
        /// <returns></returns>
        public static Color Log(Color _color, double _dLog)
        {
            return Color.FromArgb((int)Math.Log(_color.R,_dLog), (int)Math.Log(_color.G,_dLog), (int)Math.Log(_color.B,_dLog));
        }

        /// <summary>
        /// Exponential operation for all channels
        /// </summary>
        /// <param name="_color"></param>
        /// <param name="_dPow"></param>
        /// <returns></returns>
        public static Color Pow(Color _color, double _dPow)
        {
            return Color.FromArgb((int)Math.Pow(_color.R, _dPow), (int)Math.Pow(_color.G, _dPow), (int)Math.Pow(_color.B, _dPow));
        }

        /// <summary>
        /// Gets the color channel.
        /// </summary>
        /// <param name="color">The color.</param>
        /// <param name="channel">The channel.</param>
        /// <returns></returns>
        public static int GetColorChannel(Color color, RGB channel)
        {
            switch (channel)
            {
                case RGB.R:
                    return color.R;

                case RGB.G:
                    return color.G;
            }
            return color.B;
        }

        /// <summary>
        /// Randomizes the delta.
        /// </summary>
        /// <param name="_color">The _color.</param>
        /// <param name="random">The random.</param>
        /// <param name="nLevelMin">The n level min.</param>
        /// <param name="nLevelMax">The n level max.</param>
        /// <returns></returns>
        public static Color RandomizeDelta(Color _color, Random random, int nLevelMin, int nLevelMax)
        {
            int nRValue = random.Next(nLevelMin, nLevelMax);
            int nGValue = random.Next(nLevelMin, nLevelMax);
            int nBValue = random.Next(nLevelMin, nLevelMax);
            if (nRValue < 0) nRValue = 0;
            if (nGValue < 0) nGValue = 0;
            if (nBValue < 0) nBValue = 0;
            return Color.FromArgb((_color.R + nRValue) % 255, (_color.G + nGValue) % 255, (_color.B + nBValue) % 255);
        }

        /// <summary>
        /// Randomizes the gray delta.
        /// </summary>
        /// <param name="_color">The _color.</param>
        /// <param name="random">The random.</param>
        /// <param name="nLevelMin">The n level min.</param>
        /// <param name="nLevelMax">The n level max.</param>
        /// <returns></returns>
        public static Color RandomizeGrayDelta(Color _color, Random random, int nLevelMin, int nLevelMax)
        {
            int nValue = random.Next(nLevelMin, nLevelMax);
            if (nValue > 0) nValue = 0;
            return Color.FromArgb((_color.R + nValue) % 255, (_color.G + nValue) % 255, (_color.B + nValue) % 255);
        }

        /// <summary>
        /// Randomizes gray.
        /// </summary>
        /// <param name="random">The random.</param>
        /// <param name="nMinLevel">The n min level.</param>
        /// <param name="nMaxLevel">The n max level.</param>
        /// <returns></returns>
        public static Color RandomizeGray(Random random, int nMinLevel, int nMaxLevel)
        {
            int nValue = random.Next(0,255);
            return Color.FromArgb(nValue, nValue, nValue);
        }

        /// <summary>
        /// Randomizes the specified random.
        /// </summary>
        /// <param name="random">The random.</param>
        /// <param name="nMinLevel">The n min level.</param>
        /// <param name="nMaxLevel">The n max level.</param>
        /// <returns></returns>
        public static Color Randomize(Random random, int nMinLevel, int nMaxLevel)
        {
            int nR = random.Next(nMinLevel,nMaxLevel);
            int nG = random.Next(nMinLevel, nMaxLevel);
            int nB = random.Next(nMinLevel, nMaxLevel);
            if (nR < 0) nR = 0;
            if (nG < 0) nG = 0;
            if (nB < 0) nB = 0;
            return Color.FromArgb(nR, nG, nB);
        }

        /// <summary>
        /// Sorts the specified _color.
        /// </summary>
        /// <param name="_color">The _color.</param>
        /// <param name="_bUp">if set to <c>true</c> [_b up].</param>
        /// <returns></returns>
        public static Color Sort(Color _color, bool _bUp)
        {
            List<int> al = new List<int>(){_color.R, _color.G, _color.B};
            al.Sort();
            if (_bUp)
            {
                return Color.FromArgb(al[0], al[1], al[2]);
            }
            else
            {
                return Color.FromArgb(al[2], al[1], al[0]);
            }
        }

        /// <summary>
        /// Sorts the specified color space.
        /// </summary>
        /// <param name="colorSpace">The color space.</param>
        /// <param name="_bUp">if set to <c>true</c> [_b up].</param>
        /// <returns></returns>
        public static Color Sort(AbstractColorSpace colorSpace, bool _bUp)
        {
            object[] aValue = colorSpace.GetValues();
            ArrayList al = new ArrayList(aValue);
            al.Sort();
            colorSpace.SetValues(al.ToArray());
            return colorSpace.ToColor();
        }

        /// <summary>
        /// Calculates the gray value mean.
        /// </summary>
        /// <param name="r">The r.</param>
        /// <param name="g">The g.</param>
        /// <param name="b">The b.</param>
        /// <returns></returns>
        public static int CalculateGrayValueMean(int r, int g, int b)
        {
            return (r + g + b) / 3;
        }

        /// <summary>
        /// Calculates the gray value.
        /// </summary>
        /// <param name="color">The color.</param>
        /// <returns></returns>
        public static int CalculateGrayValue(Color color)
        {
            //Gray = 0.299 * R + 0.587 * G + 0.114 * B
            int gray = ((((color.R * 77) + (color.G * 151)) + (color.B * 28)) >> 8);

            if (gray < 0) gray = 0;
            if (gray > 255) gray = 255;

            return gray;
        }

        /// <summary>
        /// Normalizes the specified _color.
        /// </summary>
        /// <param name="_color">The _color.</param>
        /// <returns></returns>
        public static ColorStructF Normalize(Color _color)
        {
            return Normalize(_color, 0, 255);
        }

        /// <summary>
        /// Calculates normalized RGB Color 
        /// </summary>
        /// <param name="color"></param>
        /// <returns></returns>
        public static ColorStructF Normalize(Color color,  int _nRangeMin, int _nRangeMax)
        {
            float dSum = (float)RGBChannelSum(color);
            if (dSum == 0) dSum = 1;
            float fR = color.R / dSum;
            float fG = color.G / dSum;
            float fB = color.B / dSum;

            float fRangeValue = _nRangeMax - _nRangeMin;

            float fFactor = fRangeValue;
            fR = fR * fFactor;
            fG = fG * fFactor;
            fB = fB * fFactor;

            return new ColorStructF(fR, fG, fB);
        }

        /// <summary>
        /// Normalizes to color.
        /// </summary>
        /// <param name="_color">The _color.</param>
        /// <returns></returns>
        public static Color NormalizeToColor(Color _color)
        {
            return Normalize(_color).ToColor();
        }

        /// <summary>
        /// Colors the color of the struct to.
        /// </summary>
        /// <param name="colorStruct">The color struct.</param>
        /// <returns></returns>
        public static Color ColorStructToColor(ColorStruct colorStruct)
        {
            return Color.FromArgb(colorStruct.R, colorStruct.G, colorStruct.B);
        }

        /// <summary>
        /// Colors the color of the struct to.
        /// </summary>
        /// <param name="colorStruct">The color struct.</param>
        /// <returns></returns>
        public static Color ColorStructToColor(ColorStructF colorStruct)
        {
            return Color.FromArgb((int)colorStruct.R, (int)colorStruct.G, (int)colorStruct.B);
        }

        /// <summary>
        /// Shifts the bits of the color to the right
        /// </summary>
        /// <param name="color"></param>
        /// <param name="nBits"></param>
        /// <returns></returns>
        public static Color ShiftColorRight(Color color, int nBits)
        {
            return Color.FromArgb(color.ToArgb() >> nBits);
        }

        /// <summary>
        /// ANDs the nAnd with color.ToArgb()
        /// </summary>
        /// <param name="color"></param>
        /// <param name="nAnd"></param>
        /// <returns></returns>
        public static Color AND(Color color, int nAnd)
        {
            return Color.FromArgb(color.ToArgb() & nAnd);
        }

        public static Color AND(Color color, int nAndR, int nAndG, int nAndB)
        {
            return Color.FromArgb(color.R & nAndR, color.G & nAndG, color.B & nAndB);
        }

        /// <summary>
        /// ORs the nAnd with color.ToArgb()
        /// </summary>
        /// <param name="color"></param>
        /// <param name="nOr"></param>
        /// <returns></returns>
        public static Color OR(Color color, int nOr)
        {
            return Color.FromArgb(color.ToArgb() | nOr);
        }

        /// <summary>
        /// ORs the specified color.
        /// </summary>
        /// <param name="color">The color.</param>
        /// <param name="nOrR">The n or R.</param>
        /// <param name="nOrG">The n or G.</param>
        /// <param name="nOrB">The n or B.</param>
        /// <returns></returns>
        public static Color OR(Color color, int nOrR, int nOrG, int nOrB )
        {
            return Color.FromArgb(color.R | nOrR, color.G | nOrG, color.B | nOrB);
        }

        /// <summary>
        /// XORs the nAnd with color.ToArgb()
        /// </summary>
        /// <param name="color"></param>
        /// <param name="nXOR"></param>
        /// <returns></returns>
        public static Color XOR(Color color, int nXOR)
        {
            return Color.FromArgb(color.ToArgb() ^ nXOR);
        }

        /// <summary>
        /// XORs the nAnd with color.ToArgb()
        /// </summary>
        /// <param name="color">The color.</param>
        /// <param name="nXORR">The n XORR.</param>
        /// <param name="nXORG">The n XORG.</param>
        /// <param name="nXORB">The n XORB.</param>
        /// <returns></returns>
        public static Color XOR(Color color, int nXORR, int nXORG, int nXORB )
        {
            return Color.FromArgb(color.R ^nXORR, color.G ^ nXORG, color.B ^ nXORB);
        }

        /// <summary>
        /// zero red
        /// </summary>
        /// <param name="color"></param>
        /// <returns></returns>
        public static UInt32 ZeroRed(UInt32 color)
        {
            return color & 0xFF00FFFF;
        }

        /// <summary>
        /// zero red
        /// </summary>
        /// <param name="color"></param>
        /// <returns></returns>
        public static Color ZeroRed(Color color)
        {
            return Color.FromArgb(0, color.G, color.B);
        }

        /// <summary>
        /// zero green
        /// </summary>
        /// <param name="color"></param>
        /// <returns></returns>
        public static UInt32 ZeroGreen(UInt32 color)
        {
            return color & 0xFFFF00FF;
        }

        /// <summary>
        /// zero green
        /// </summary>
        /// <param name="color"></param>
        /// <returns></returns>
        public static Color ZeroGreen(Color color)
        {
            return Color.FromArgb(color.R, 0, color.B);
        }

        /// <summary>
        /// Zeroes blue
        /// </summary>
        /// <param name="color"></param>
        /// <returns></returns>
        public static UInt32 ZeroBlue(UInt32 color)
        {
            return color & 0xFFFFFF00;
        }

        /// <summary>
        /// Zeroes blue
        /// </summary>
        /// <param name="color"></param>
        /// <returns></returns>
        public static Color ZeroBlue(Color color)
        {
            return Color.FromArgb(color.R, color.G, 0);
        }

        /// <summary>
        /// sets red to the max value 255
        /// </summary>
        /// <param name="color"></param>
        /// <returns></returns>
        public static Color MaxRed(Color color)
        {
            return Color.FromArgb(255, color.G, color.B);
        }

        /// <summary>
        /// Sets green to the max value 255
        /// </summary>
        /// <param name="color"></param>
        /// <returns></returns>
        public static Color MaxGreen(Color color)
        {
            return Color.FromArgb(color.R, 255, color.B);
        }

        /// <summary>
        /// Sets the blue channel to the max value 255
        /// </summary>
        /// <param name="color"></param>
        /// <returns></returns>
        public static Color MaxBlue(Color color)
        {
            return Color.FromArgb(color.R, color.B, 255);
        }

        /// <summary>
        /// Get maximum yellow.
        /// </summary>
        /// <param name="color">The color.</param>
        /// <returns></returns>
        public static Color MaxYellow(Color color)
        {
            return Color.FromArgb(color.R, color.G, 255);
        }

        /// <summary>
        /// Calculates the color distance between color 1 and color 2
        /// </summary>
        /// <param name="color1"></param>
        /// <param name="color2"></param>
        /// <returns></returns>
        public static int Distance(Color color1, Color color2)
        {
            return (int)Math.Sqrt(
                (double)((((color1.R - color2.R) * (color1.R - color2.R))
                + ((color1.G - color2.G) * (color1.G - color2.G)))
                + ((color1.B - color2.B) * (color1.B - color2.B)))
            );
        }

        /// <summary>
        /// returns square of color distance.
        /// </summary>
        /// <param name="color1">The color1.</param>
        /// <param name="color2">The color2.</param>
        /// <returns></returns>
        public static int DistanceSquared(Color color1, Color color2)
        {
            int nR1 = color1.R;
            int nG1 = color1.G;
            int nB1 = color1.B;

            int nRedDistance = color2.R - nR1;
            int nGreenDistance = color2.G - nG1;
            int nBlueDistance = color2.B - nB1;

            return nRedDistance * nRedDistance + nGreenDistance * nGreenDistance + nBlueDistance * nBlueDistance;
        }

        /// <summary>
        /// returns city block distance of two colors
        /// </summary>
        /// <param name="color1"></param>
        /// <param name="color2"></param>
        /// <returns></returns>
        public static int CityBlockDistance(Color color1, Color color2)
        {
            return Math.Abs((color1.R - color2.R) + (color1.G - color2.G) + (color1.B - color2.B));            
        }

        /// <summary>
        /// returns chess board distance of two colors
        /// </summary>
        /// <param name="color1"></param>
        /// <param name="color2"></param>
        /// <returns></returns>
        public static int ChessBoardDistance(Color color1, Color color2)
        {
            return Math.Max(color1.R, color2.R) + Math.Max(color1.G, color2.G) + Math.Max(color1.B, color2.B);
        }

        /// <summary>
        /// returns the maximum distance.
        /// </summary>
        /// <returns></returns>
        public static int MaxDistance()
        {
            return Distance(Definitions.Black, Definitions.White);
        }

        /// <summary>
        /// returns the maximum distance
        /// </summary>
        /// <returns></returns>
        public static double MaxDistance2()
        {
            return Distance2(Definitions.Black, Definitions.White);
        }

        /// <summary>
        /// returns the minimum distance
        /// </summary>
        /// <returns></returns>
        public static int MinDistance()
        {
            return Distance(Definitions.White, Definitions.White);
        }

        /// <summary>
        /// returns the minimum distance
        /// </summary>
        /// <returns></returns>
        public static double MinDistance2()
        {
            return Distance2(Definitions.White, Definitions.White);
        }

        /// <summary>
        /// The proposed algorithm (used by our products EGI, AniSprite and PaletteMaker) 
        /// is a combination both weighted Euclidean distance functions, 
        /// where the weight factors depend on how big the "red" component of the colour is. 
        /// First one calculates the mean level of "red" and then weights the R and B signals 
        /// as a function of the mean red level. 
        /// The distance between colours C1 and C2 
        /// (where each of the red, green and blue channels has a range of 0-255) is: 
        /// 
        /// This formula has results that are very close to L*u*v* 
        /// (with the modified lightness curve) and, more importantly,
        /// it is a more stable algorithm: it does not have a range of colours where it suddenly 
        /// gives far from optimal results. 
        /// 
        /// The weights of the formula could be optimized further, but again,
        /// the selection of the closest colour is subjective. 
        /// 
        /// The goal was to find a reasonable compromise. 
        /// </summary>
        /// <param name="e1"></param>
        /// <param name="e2"></param>
        /// <returns></returns>
        public static double Distance2(Color e1, Color e2)
        {
            long rmean = ((long)e1.R + (long)e2.R) / 2;
            long r = (long)e1.R - (long)e2.R;
            long g = (long)e1.G - (long)e2.G;
            long b = (long)e1.B - (long)e2.B;
            return Math.Sqrt((((512 + rmean) * r * r) >> 8) + 4 * g * g + (((767 - rmean) * b * b) >> 8));
        }

        /// <summary>
        /// Extracts the opaque alpha channel.
        /// </summary>
        /// <param name="color1">The color1.</param>
        /// <param name="color2">The color2.</param>
        /// <returns></returns>
        public static UInt32 ExtractOpaqueAlphaChannel(Color color1, Color color2)
        {
            return ((UInt32)color1.ToArgb() ^ (UInt32)color2.ToArgb()) | (0xFF000000);
        }

        /// <summary>
        /// Builds the pixel.
        /// </summary>
        /// <param name="R">The R.</param>
        /// <param name="G">The G.</param>
        /// <param name="B">The B.</param>
        /// <returns></returns>
        public static UInt32 BuildPixel(UInt32 R, UInt32 G, UInt32 B)
        { 
            return (((R << 16) | (G << 8) | B) | 0xff000000); 
        }

        /// <summary>
        /// Extracts the color of the opacity.
        /// </summary>
        /// <param name="_color">The _color.</param>
        /// <returns></returns>
        public static Color ExtractOpacityColor(Color _color)
        {
            return Color.FromArgb(_color.A, 0, 0, 0);
        }

        /// <summary>
        /// Extracts the color of the red channel.
        /// </summary>
        /// <param name="_color">The _color.</param>
        /// <returns></returns>
        public static Color ExtractRedColor(Color _color)
        {
            return Color.FromArgb(_color.R, 0, 0);
        }

        /// <summary>
        /// Extracts the red amount of the color
        /// </summary>
        /// <param name="color"></param>
        /// <returns></returns>
        public static int ExtractRed(Color color)
        {
            return (color.ToArgb() & 0x00FF0000)>>16;
        }

        /// <summary>
        /// Extracts the color of the green channel.
        /// </summary>
        /// <param name="_color">The _color.</param>
        /// <returns></returns>
        public static Color ExtractGreenColor(Color _color)
        {
            return Color.FromArgb(0, _color.G, 0);
        }

        /// <summary>
        /// extracts the green amount of a color
        /// </summary>
        /// <param name="color"></param>
        /// <returns></returns>
        public static int ExtractGreen(Color color)
        {
            return (color.ToArgb() & 0x0000FF00)>>8;
        }

        /// <summary>
        /// Extracts the color of the blue.
        /// </summary>
        /// <param name="_color">The _color.</param>
        /// <returns></returns>
        public static Color ExtractBlueColor(Color _color)
        {
            return Color.FromArgb(0, 0, _color.B);
        }

        /// <summary>
        /// extracts the blue amount of a color
        /// </summary>
        /// <param name="color"></param>
        /// <returns></returns>
        public static int ExtractBlue(Color color)
        {
            return color.ToArgb() & 0x000000FF;
        }

        /// <summary>
        /// Pixel_builds the specified R.
        /// </summary>
        /// <param name="R">The R.</param>
        /// <param name="G">The G.</param>
        /// <param name="B">The B.</param>
        /// <returns></returns>
        UInt32 pixel_build(UInt32 R, UInt32 G, UInt32 B)
        { 
            return (((R << 16) | (G << 8) | B) | 0xff000000); 
        }

        /// <summary>
        /// Gets the channel ratios: R/B, B/G, R/G
        /// </summary>
        /// <param name="color"></param>
        /// <param name="fBG"></param>
        /// <param name="fRB"></param>
        /// <param name="fRG"></param>
        public static void GetChannelRatios(Color color, out float fBG, out float fRB, out float fRG)
        {
            float fR = color.R;
            float fG = color.G;
            float fB = color.B;

            if (fR == 0) fR = 1;
            if (fG == 0) fG = 1;
            if (fB == 0) fB = 1;
            float fRatioRB = fR / fB;
            float fRatioBG = fB / fG;
            float fRatioRG = fR / fG;

            fRB = fRatioRB;
            fBG = fRatioBG;
            fRG = fRatioRG;
        }

        /// <summary>
        /// Channel ratio of a ratio within a tolerance
        /// </summary>
        /// <param name="color"></param>
        /// <param name="fValue1"></param>
        /// <param name="fValue2"></param>
        /// <param name="fTolerance"></param>
        /// <returns></returns>
        public static bool ChannelRatio(Color color, float fValue1, float fValue2, float fTolerance)
        {
            if (color.B == 0 || color.G == 0)
            {
                return false;
            }
            
            float fRatioRB = color.R / color.B;
            float fRatioBG = color.B / color.G;

            if (Math.Abs(fRatioRB - fValue1) <= fTolerance && Math.Abs(fRatioBG - fValue2) <= fTolerance)
            {
                return true;
            }
            return false;
        }

        /// <summary>
        /// Tests if the Color is a multiple of gray
        /// </summary>
        /// <param name="color1"></param>
        /// <param name="color2"></param>
        /// <param name="fTolerance"></param>
        /// <returns></returns>
        public static bool IsMultipleOfGray(Color color1, Color color2, float fTolerance)
        {
            if (color2.R != 0 && color2.G != 0 && color2.B != 0)
            {
                float fR = (float)color1.R / (float)color2.R;
                float fG = (float)color1.G / (float)color2.G;
                float fB = (float)color1.B / (float)color2.B;
                float fValue = Math.Abs(Math.Abs(fR - fG) - Math.Abs(fG - fB));
                return fValue <= fTolerance;
            }
            return false;
        }

        /// <summary>
        /// Tests if color 1 is multiple of color 2
        /// </summary>
        /// <param name="color1"></param>
        /// <param name="color2"></param>
        /// <param name="fRFactor"></param>
        /// <param name="fGFactor"></param>
        /// <param name="fBFactor"></param>
        /// <param name="fTolerance"></param>
        /// <returns></returns>
        public static bool IsMultipleOf(Color color1, Color color2, float fRFactor, float fGFactor, float fBFactor, float fTolerance)
        {
            Color colorMax = ColorMax(color1, color2);
            Color colorMin = ColorMin(color1, color2);

            if (colorMin.R != 0 && colorMin.G != 0 && colorMin.B != 0)
            {
                float fR = colorMax.R / colorMin.R;
                float fG = colorMax.G / colorMin.G;
                float fB = colorMax.B / colorMin.B;

                if (Math.Abs(fR - fRFactor) <= fTolerance
                    && Math.Abs(fG - fGFactor) <= fTolerance
                    && Math.Abs(fB - fBFactor) <= fTolerance)
                {
                    return true;
                }
                return false;
            }
            return false;
        }

        /// <summary>
        /// Tests also if color 1 is multiple of color 2, but uses the channel ratios
        /// </summary>
        /// <param name="color1"></param>
        /// <param name="color2"></param>
        /// <returns></returns>
        public static bool IsMultipleOf(Color color1, Color color2)
        {
            if (color1.R != color2.R && color1.G != color2.G && color1.B != color2.B)
            {
                float fR = (color1.R + 1) / (color2.R + 1);
                float fG = (color1.G + 1) / (color2.G + 1);
                float fB = (color1.B + 1) / (color2.B + 1);

                return (fR == fG && fG == fB);
            }
            return false;
        }

        /// <summary>
        /// Tests also if color 1 is multiple of color 2, but uses the channel ratios
        /// </summary>
        /// <param name="color1"></param>
        /// <param name="color2"></param>
        /// <returns></returns>
        public static bool ChannelRatioEqual(Color color1, Color color2)
        {
            float fRG1 = (float)(color1.R + 1) / (float)(color1.G + 1);
            float fGB1 = (float)(color1.G + 1) / (float)(color1.B + 1);

            float fRG2 = (float)(color2.R + 1) / (float)(color2.G + 1);
            float fGB2 = (float)(color2.G + 1) / (float)(color2.B + 1);

            return (fRG1 == fRG2 && fGB1 == fGB2);
        }

        /// <summary>
        /// Returns the color with the bigger RGB-Components
        /// All have to be bigger for the Color to be returned
        /// </summary>
        /// <param name="color1"></param>
        /// <param name="color2"></param>
        /// <returns></returns>
        public static Color ColorMax(Color color1, Color color2)
        {
            if (color1.R > color2.R && color1.G > color2.G && color1.B > color2.B)
            {
                return color1;
            }
            else if (color2.R > color1.R && color2.G > color1.G && color2.B > color1.B)
            {
                return color2;
            }
            //if equal return TRANSPARENT color
            return Color.Transparent;
        }

        /// Returns the color with the smaller RGB-Components
        /// All have to be smaller for the Color to be returned
        public static Color ColorMin(Color color1, Color color2)
        {
            if (color1.R < color2.R && color1.G < color2.G && color1.B < color2.B)
            {
                return color1;
            }
            else if (color2.R < color1.R && color2.G < color1.G && color2.B < color1.B)
            {
                return color2;
            }
            //if equal return TRANSPARENT color
            return Color.Transparent;
        }

        /// <summary>
        /// Rotates the RGB-Components
        /// </summary>
        /// <param name="color"></param>
        /// <returns></returns>
        public static Color RotateChannels(Color color)
        {
            return Color.FromArgb(color.B, color.R, color.G);
        }

        /// <summary>
        /// Exchanges the color Components as in given string
        /// 
        /// =================================================
        /// e.g.: 
        /// 
        /// 
        /// Parameters: 
        /// Color = 0,255,127 -> bgr
        /// 
        /// result: 
        /// Color = 127, 255, 0
        /// 
        /// ================================================
        /// It's also possible to exchange colors:
        /// 
        /// Parameters:
        /// Color = 0, 30, 60 -> bbg
        /// 
        /// result:
        /// Color = 60, 60, 30
        /// </summary>
        /// <param name="color"></param>
        /// <param name="sRGB"></param>
        /// <returns></returns>
        public static Color ExchangeChannels(Color color, string sRGB)
        {
            if (sRGB.Length > 3) return Color.Transparent;

            Dictionary<char,int> dictionary = new Dictionary<char,int>();
            dictionary.Add('r', color.R);
            dictionary.Add('g', color.G);
            dictionary.Add('b', color.B);

            return Color.FromArgb(
                dictionary[sRGB[0]],
                dictionary[sRGB[1]],
                dictionary[sRGB[2]]
            );
        }

        /// <summary>
        /// Gets the max channel color.
        /// </summary>
        /// <param name="_color">The _color.</param>
        /// <returns></returns>
        public static Color MaxChannelColor(Color _color)
        {
            int nValue = MaxChannel(_color);
            return Color.FromArgb(nValue, nValue, nValue);
        }

        /// <summary>
        /// returns the biggest value of R,G and B as an int
        /// </summary>
        /// <param name="color"></param>
        /// <returns></returns>
        public static int MaxChannel(Color color)
        {
            return Math.Max(Math.Max(color.R, color.G), color.B);
        }

        /// <summary>
        /// Photoshop Saturation
        /// </summary>
        /// <param name="color"></param>
        /// <returns></returns>
        public static int PhotoshopSaturation(Color color)
        {
            return Math.Max(color.R, Math.Max(color.G, color.B)) - Math.Min(color.R, Math.Min(color.G, color.B));
        }

        /// <summary>
        /// Gets the channel.
        /// </summary>
        /// <param name="_nValue">The _n value.</param>
        /// <returns></returns>
        public static int GetChannel(int _nValue)
        {
            if ((_nValue < 0x100) & (_nValue >= 0))
            {
                return _nValue;
            }
            if (_nValue > 0xff)
            {
                return 0xff;
            }
            return 0;
        }

        /// <summary>
        /// Gets the channel.
        /// </summary>
        /// <param name="_color">The _color.</param>
        /// <param name="_chChar">The _CH char.</param>
        /// <returns></returns>
        public static int GetChannel(Color _color, char _chChar)
        { 
            switch(_chChar)
            {
                case 'R':
                    return _color.R;

                case 'G':
                    return _color.G;

                case 'B':
                    return _color.B;

                default:
                    return -1;
            }
        }

        /// <summary>
        /// Gets the dispersion.
        /// </summary>
        /// <param name="bmp">The BMP.</param>
        /// <returns></returns>
        public static Color GetDispersion(UnsafeBitmap bmp)
        {
            return Color.FromArgb((int)GetDispersion(bmp, RGB.R), (int)GetDispersion(bmp, RGB.G), (int)GetDispersion(bmp, RGB.B));
        }

        /// <summary>
        /// Gets the dispersion.
        /// </summary>
        /// <param name="bmp">The BMP.</param>
        /// <param name="channel">The channel.</param>
        /// <returns></returns>
        public static double GetDispersion(UnsafeBitmap bmp, RGB channel)
        {
            double d = 0.0;
            double e = GetMeanValue(bmp, channel);
            for (int i = 0; i < bmp.Width; i++)
            {
                for (int j = 0; j < bmp.Height; j++)
                {
                    double difference = GetColorChannel(bmp.GetPixel(i, j), channel) - e;
                    d += difference * difference;
                }
            }
            d /= (double)(bmp.Width * bmp.Height);
            return Math.Sqrt(d);
        }

        /// <summary>
        /// Gets the mean value.
        /// </summary>
        /// <param name="bmp">The BMP.</param>
        /// <returns></returns>
        public static Color GetMeanValue(UnsafeBitmap bmp)
        {
            return Color.FromArgb((int)GetMeanValue(bmp, RGB.R), (int)GetMeanValue(bmp, RGB.G), (int)GetMeanValue(bmp, RGB.B));
        }

        /// <summary>
        /// Gets the mean value.
        /// </summary>
        /// <param name="bmp">The BMP.</param>
        /// <param name="channel">The channel.</param>
        /// <returns></returns>
        public static double GetMeanValue(UnsafeBitmap bmp, RGB channel)
        {
            double e = 0.0;
            for (int i = 0; i < bmp.Width; i++)
            {
                for (int j = 0; j < bmp.Height; j++)
                {
                    e += GetColorChannel(bmp.GetPixel(i, j), channel);
                }
            }
            return (e / ((double)(bmp.Width * bmp.Height)));
        }

        /// <summary>
        /// Gets the "corrected" color.
        /// </summary>
        /// <param name="r">The r.</param>
        /// <param name="g">The g.</param>
        /// <param name="b">The b.</param>
        /// <returns></returns>
        public static Color GetCorrectedColor(int r, int g, int b)
        {
            return Color.FromArgb(GetChannel(r), GetChannel(g), GetChannel(b));
        }

        /// <summary>
        /// Superpositions the color.
        /// </summary>
        /// <param name="c1">The c1.</param>
        /// <param name="c2">The c2.</param>
        /// <param name="k">The k.</param>
        /// <returns></returns>
        public static Color SuperpositionColor(Color c1, Color c2, double k)
        {
            return GetCorrectedColor((int)((c1.R * k) + (c2.R * (1.0 - k))), (int)((c1.G * k) + (c2.G * (1.0 - k))), (int)((c1.B * k) + (c2.B * (1.0 - k))));
        }

        /// <summary>
        /// Get mid channel color
        /// </summary>
        /// <param name="color"></param>
        /// <returns></returns>
        public static Color MidChannelColor(Color color)
        {
            int nValue = MidChannel(color);
            return Color.FromArgb(nValue, nValue, nValue);
        }

        /// <summary>
        /// Gets the mid channel color.
        /// </summary>
        /// <param name="color">The color.</param>
        /// <returns></returns>
        public static int MidChannel(Color color)
        {
            return Sort(color, true).G;
        }

        /// <summary>
        /// Mins the color of the channel.
        /// </summary>
        /// <param name="_abstractColorSpace">The _abstract color space.</param>
        /// <returns></returns>
        public static Color MinChannelColor(AbstractColorSpace _abstractColorSpace)
        {
            int nValue = MinChannel(_abstractColorSpace);
            _abstractColorSpace.SetValues(new object[]{nValue,nValue,nValue});
            return _abstractColorSpace.ToColor();
        }

        /// <summary>
        /// Gets the min channel color.
        /// </summary>
        /// <param name="color">The color.</param>
        /// <returns></returns>
        public static Color MinChannelColor(Color color)
        {
            int nValue = MinChannel(color);
            return Color.FromArgb(nValue, nValue, nValue);
        }

        /// <summary>
        /// Mins the channel.
        /// </summary>
        /// <param name="_abstractColorSpace">The _abstract color space.</param>
        /// <returns></returns>
        public static int MinChannel(AbstractColorSpace _abstractColorSpace)
        {
            object[] aObject = _abstractColorSpace.GetValues();
            return Math.Min(Math.Min((int)aObject[0], (int)aObject[1]), (int)aObject[2]);
        }

        /// <summary>
        /// returns the smallest value of R,G and B as an int
        /// </summary>
        /// <param name="color"></param>
        /// <returns></returns>
        public static int MinChannel(Color color)
        {
            return Math.Min(Math.Min(color.R, color.G), color.B);
        }

        /// <summary>
        /// returns TRUE if the color is completely WHITE
        /// </summary>
        /// <param name="color"></param>
        /// <returns></returns>
        public static bool IsWhite(Color color)
        {
            return color.R == 0xFF && color.G == 0xFF && color.B == 0xFF;
        }

        /// <summary>
        /// returns TRUE if the color is completely BLACK
        /// </summary>
        /// <param name="color"></param>
        /// <returns></returns>
        public static bool IsBlack(Color color)
        {
            return color.R == 0x00 &&  color.B == 0x00 && color.G == 0x00;
        }

        /// <summary>
        /// Returns true if all Color Channels are equal (R, G, B) 
        /// </summary>
        /// <param name="color1"></param>
        /// <param name="color2"></param>
        /// <returns></returns>
        public static bool IsEqualColors(Color color1, Color color2)
        {
            return (((color1.R == color2.R) & (color1.B == color2.B)) & (color1.G == color2.G));
        }

        /// <summary>
        /// Sets all values to nValue
        /// </summary>
        /// <param name="_color"></param>
        /// <param name="_nValue"></param>
        /// <returns></returns>
        public static Color AllValuesTo(Color _color, int _nValue)
        {
            _color = Color.FromArgb(_nValue, _nValue, _nValue);
            return _color;
        }

        /// <summary>
        /// Sets all the values to n.
        /// </summary>
        /// <param name="_nValue">The _n value.</param>
        /// <returns></returns>
        public static Color AllValuesTo(int _nValue)
        {
            return Color.FromArgb(_nValue, _nValue, _nValue);
        }

        /// <summary>
        /// return gray color.
        /// </summary>
        /// <param name="_color">The _color.</param>
        /// <returns></returns>
        public static Color GrayColor(Color _color)
        {
            int nValue = Gray(_color);
            return Color.FromArgb(nValue, nValue, nValue);
        }
        /// <summary>
        /// Gets the gray value of given color
        /// </summary>
        /// <param name="color"></param>
        /// <returns></returns>
        public static int Gray(Color color)
        {
            return (int)(((color.R * 0.11) + (color.G * 0.59)) + (color.B * 0.3));
        } 

        /// <summary>
        /// Converts Color to YBCR
        /// </summary>
        /// <param name="color"></param>
        /// <returns></returns>
        public static YCbCr ColorToYBCR(Color color)
        {
            return new YCbCr(color);
        }

        /// <summary>
        /// Rounds the color components
        /// </summary>
        /// <param name="_color"></param>
        /// <returns></returns>
        public static Color ColorComponentRound(Color _color)
        {
            return ColorComponentRound(_color, MidpointRounding.ToEven, 10);
        }

        /// <summary>
        /// Enhances the color (i.e. add a certain value to RGB values)
        /// </summary>
        /// <param name="_color"></param>
        /// <returns></returns>
        public static Color EnhanceColor(Color _color)
        {
            return EnhanceColor(_color, 10, 1);
        }

        /// <summary>
        /// Add nEnhance to RGB components of color
        /// </summary>
        /// <param name="_color"></param>
        /// <param name="nEnhance"></param>
        /// <returns></returns>
        public static Color EnhanceColor(Color _color, int nEnhance)
        {
            return EnhanceColor(_color, nEnhance, 1);
        }

        /// <summary>
        /// returns true if the given values could be the components for
        /// a valid Color, otherwise false is returned
        /// </summary>
        /// <param name="r"></param>
        /// <param name="g"></param>
        /// <param name="b"></param>
        /// <returns></returns>
        public static bool LimitsOk(int r, int g, int b)
        {
            return r > -1 && r < 256 && g > -1 && g < 256 && b > -1 && b < 256;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="_color"></param>
        /// <param name="_colorAdd"></param>
        /// <returns></returns>
        public Color Add(Color _color, Color _colorAdd)
        {
            return Color.FromArgb(_color.R + _colorAdd.R, _color.G + _colorAdd.G, _color.B + _colorAdd.B);
        }

        /// <summary>
        /// Adds the specified _color.
        /// </summary>
        /// <param name="_color">The _color.</param>
        /// <param name="_nValue">The _n value.</param>
        /// <returns></returns>
        public Color Add(Color _color, int _nValue)
        {
            return Color.FromArgb(_color.R + _nValue, _color.G + _nValue, _color.B + _nValue);
        }

        /// <summary>
        /// Subs the specified _color.
        /// </summary>
        /// <param name="_color">The _color.</param>
        /// <param name="_colorSub">The _color sub.</param>
        /// <returns></returns>
        public Color Sub(Color _color, Color _colorSub)
        {
            return Color.FromArgb(_color.R - _colorSub.R, _color.G - _colorSub.G, _color.B - _colorSub.B);
        }

        /// <summary>
        /// Subs the specified _color.
        /// </summary>
        /// <param name="_color">The _color.</param>
        /// <param name="_nValue">The _n value.</param>
        /// <returns></returns>
        public Color Sub(Color _color, int _nValue)
        {
            return Color.FromArgb(_color.R - _nValue, _color.G - _nValue, _color.B - _nValue);
        }

        /// <summary>
        /// Divides the specified _color.
        /// </summary>
        /// <param name="_color">The _color.</param>
        /// <param name="_colorDiv">The _color div.</param>
        /// <returns></returns>
        public Color Div(Color _color, Color _colorDiv)
        {
            return Color.FromArgb(_color.R / _colorDiv.R, _color.G / _colorDiv.G, _color.B / _colorDiv.B);
        }

        /// <summary>
        /// Multiplicates the specified _color.
        /// </summary>
        /// <param name="_color">The _color.</param>
        /// <param name="_nValue">The _n value.</param>
        /// <returns></returns>
        public Color Mul(Color _color, int _nValue)
        {
            return Color.FromArgb(_color.R * _nValue, _color.G * _nValue, _color.B * _nValue);
        }

        /// <summary>
        /// Multiplicates the specified _color.
        /// </summary>
        /// <param name="_color">The _color.</param>
        /// <param name="_colorDiv">The _color div.</param>
        /// <returns></returns>
        public Color Mul(Color _color, Color _colorDiv)
        {
            return Color.FromArgb(_color.R * _colorDiv.R, _color.G * _colorDiv.G, _color.B * _colorDiv.B);
        }

        /// <summary>
        /// Enhance Color
        /// </summary>
        /// <param name="_color"></param>
        /// <param name="nEnhance"></param>
        /// <param name="nFactor"></param>
        /// <returns></returns>
        public static Color EnhanceColor(Color _color, int nEnhance, int nFactor)
        {
            int nColor = RGBMax(_color, true);

            int nR = -1;
            int nG = -1;
            int nB = -1;
            int nResult = nEnhance * nFactor;
            if ((nColor & 0xFF0000) > 0)
            {
                nR = _color.R + nResult;
                nG = _color.G - nResult;
                nB = _color.B - nResult;
            }
            else if ((nColor & 0x00FF00) > 0)
            {
                nR = _color.R - nResult;
                nG = _color.G + nResult;
                nB = _color.B - nResult;
            }
            else if ((nColor & 0x0000FF) > 0)
            {
                nR = _color.R - nResult;
                nG = _color.G - nResult;
                nB = _color.B + nResult;
            }

            if (LimitsOk(nR, nG, nB))
            {
                _color = Color.FromArgb(nR, nG, nB);
            }

            return _color;
        }

        /// <summary>
        /// Determines whether [is inverted color] [the specified color1].
        /// </summary>
        /// <param name="color1">The color1.</param>
        /// <param name="color2">The color2.</param>
        /// <returns>
        /// 	<c>true</c> if [is inverted color] [the specified color1]; otherwise, <c>false</c>.
        /// </returns>
        public static bool IsInvertedColor(Color color1, Color color2)
        {
            return (color1.R == 255 - color2.R && color1.G == 255 - color2.G && color1.B == 255 - color2.B);
        }

        /// <summary>
        /// Rounds RGB to a certain rounding value
        /// </summary>
        /// <returns></returns>
        public static Color ColorComponentRound(Color _color, MidpointRounding _midPountRounding, int nRounding)
        {
            int nR = _color.R;
            int nG = _color.G;
            int nB = _color.B;

            if (nRounding == 0) nRounding = 1;
            int nRMod = (nR % nRounding);
            int nGMod = (nG % nRounding);
            int nBMod = (nB % nRounding);

            nR -= nRMod;
            nG -= nGMod;
            nB -= nBMod;
            
            switch (_midPountRounding)
            {
                case MidpointRounding.AwayFromZero:
                    break;

                case MidpointRounding.ToEven:
                    if (nR > 4)
                    {
                        nR += nRounding;
                    }
                    if (nG > 4)
                    {
                        nG += nRounding;
                    }
                    if (nB > 4)
                    {
                        nB += nRounding;
                    }
                    break;
            }
            if (nR > 255) nR = 255;
            if (nG > 255) nG = 255;
            if (nB > 255) nB = 255;
            return Color.FromArgb(nR, nG, nB);
        }

        /// <summary>
        /// Returns the biggest component.
        /// if the color is 255, 10, 10 return = 255
        /// if the color is 0, 255, 10 return 255
        /// if the color is 0, 0, 255 return 255
        /// if the color is 0, 255, 255, return -1
        /// </summary>
        /// <param name="_color">The _color.</param>
        /// <returns></returns>
        public static int RGBMax(Color _color)
        {
            if (_color.R > _color.G && _color.R > _color.B)
            {
                return _color.R;
            }
            else if (_color.G > _color.B && _color.G > _color.R)
            {
                return _color.G;
            }
            else if (_color.B > _color.G && _color.B > _color.R)
            {
                return _color.B;
            }
            return -1;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="nR"></param>
        /// <param name="nG"></param>
        /// <param name="nB"></param>
        /// <returns></returns>
        public static string RGBMaxLetters(int nR, int nG, int nB)
        {
            return RGBMaxLetters(Color.FromArgb(nR, nG, nB));
        }

        /// <summary>
        /// Returns the component(s) with the biggest components.
        /// e.g.: 
        /// 200, 100,   0 returns: R
        /// 0,     0, 255 returns: B
        /// 0,   255, 255 returns BG
        /// 255, 255, 255 returns RBG
        /// and so on.
        /// </summary>
        /// <param name="_color"></param>
        /// <returns></returns>
        public static string RGBMaxLetters(Color _color)
        {
            int nColor = RGBMax(_color, true);
            string sLetter = string.Empty;
            if (_color.R == _color.G && _color.B < _color.R)
            {
                return "RG";
            }
            else if (_color.R == _color.B && _color.G < _color.R)
            {
                return "RB";
            }
            else if (_color.B == _color.G && _color.R < _color.B)
            {
                return "BG";
            }
            else if (_color.R == _color.G && _color.G == _color.B)
            {
                return "RBG";
            }
            if ((nColor & 0xFF0000) > 0)
            {
                sLetter = "R";
            }
            else if ((nColor & 0x00FF00) > 0)
            {
                sLetter = "G";
            }
            else if ((nColor & 0x0000FF) > 0)
            {
                sLetter = "B";
            }
            return sLetter;
        }


        /// <summary>
        /// gets the maxcolor.
        /// </summary>
        /// <param name="_color">The _color.</param>
        /// <param name="_bGetHexValue">if set to <c>true</c> [_b get hex value].</param>
        /// <returns></returns>
        public static int RGBMax(Color _color, bool _bGetHexValue)
        {
            if (!_bGetHexValue)
            {
                return RGBMax(_color);
            }
            if (_color.R > _color.G && _color.R > _color.B)
            {
                return _color.R * 0x10000;
            }
            else if (_color.G > _color.B && _color.G > _color.R)
            {
                return _color.G * 0x100;
            }
            else if (_color.B > _color.G && _color.B > _color.R)
            {
                return _color.B;
            }
            return -1;
        }

        /// <summary>
        /// Returns an average Saturation value from aSaturation
        /// </summary>
        /// <param name="aSaturation"></param>
        /// <returns></returns>
        public static float AverageSaturation(List<float> aSaturation)
        {
            float fSum = 0.0f;
            for (int i = 0; i < aSaturation.Count; i++)
            {
                fSum += aSaturation[i];
            }
            int nSaturationCount = aSaturation.Count;
            if (nSaturationCount > 0)
            {
                return fSum / nSaturationCount;
            }
            return 0;
        }

        /// <summary>
        /// Returns an average luminance value from aLuminance
        /// </summary>
        /// <param name="aLuminance"></param>
        /// <returns></returns>
        public static float AverageLuminance(List<float> aLuminance)
        {
            float fSum = 0.0f;
            for (int i = 0; i < aLuminance.Count; i++)
            {
                fSum += aLuminance[i];
            }
            int nLuminanceCount = aLuminance.Count;
            if (nLuminanceCount > 0)
            {
                return fSum / nLuminanceCount;
            }
            return 0;
        }

        /// <summary>
        /// Returns an average brightness value from aBrightness
        /// </summary>
        /// <param name="aBrightness"></param>
        /// <returns></returns>
        public static float AverageBrightness(List<float> aBrightness)
        {
            float fSum = 0.0f;
            for (int i = 0; i < aBrightness.Count; i++)
            {
                fSum += aBrightness[i];
            }
            int nBrightnessCount = aBrightness.Count;
            if (nBrightnessCount > 0)
            {
                return fSum / nBrightnessCount;
            }
            return 0;
        }

        /// <summary>
        /// Averages the values.
        /// </summary>
        /// <param name="aValues">A values.</param>
        /// <returns></returns>
        public static float AverageValues(List<float> aValues)
        {
            float fSum = 0.0f;
            for (int i = 0; i < aValues.Count; i++)
            {
                fSum += aValues[i];
            }
            int nBrightnessCount = aValues.Count;
            if (nBrightnessCount > 0)
            {
                return fSum / nBrightnessCount;
            }
            return 0;
        }

        /// <summary>
        /// Returns an average hue value from aHue
        /// </summary>
        /// <param name="aHue"></param>
        /// <returns></returns>
        public static float AverageHue(List<float> aHue)
        {
            float fSum = 0.0f;
            for (int i = 0; i < aHue.Count; i++)
            {
                fSum += aHue[i];
            }
            int nHueCount = aHue.Count;
            if (nHueCount > 0)
            {
                return fSum / nHueCount;
            }
            return 0;
        }

        /// <summary>
        /// Averages the channels.
        /// </summary>
        /// <param name="r">The r.</param>
        /// <param name="g">The g.</param>
        /// <param name="b">The b.</param>
        /// <returns></returns>
        public static int ChannelAverage(int r, int g, int b)
        {
            return (int)((r + g + b) / 3.0f);
        }

        /// <summary>
        /// Gets the channel average color
        /// </summary>
        /// <param name="_color"></param>
        /// <returns></returns>
        public static Color ChannelAverageColor(Color _color)
        {
            double dAverage = (_color.R + _color.G + _color.B) / 3.0f;
            int nAverage = (int)dAverage;
            return Color.FromArgb(nAverage, nAverage, nAverage);
        }

        /// <summary>
        /// Gets the channel average color
        /// </summary>
        /// <param name="_aColor"></param>
        /// <returns></returns>
        public static Color AverageColor(Color[] _aColor)
        {
            List<Color> aColor = new List<Color>();
            aColor.AddRange(_aColor);
            return AverageColor(aColor);
        }

        /// <summary>
        /// returns how many of the colors in _aColor are like _color
        /// </summary>
        /// <param name="_aColor">Color of the _a.</param>
        /// <param name="_color">The _color.</param>
        /// <returns></returns>
        public static int ColorCount(Color[] _aColor, Color _color)
        {
            int nCount = 0;
            foreach (Color color in _aColor)
            {
                if (color.Equals(_color))
                {
                    nCount++;
                }
            }
            return nCount;
        }

        /// <summary>
        /// Returns an average color from aColor
        /// </summary>
        /// <param name="aColor"></param>
        /// <returns></returns>
        public static Color AverageColor(List<Color> aColor)
        {
            Color colorAverage = Color.Transparent;
            int nR = 0;
            int nG = 0;
            int nB = 0;
            int nColorCount = aColor.Count;
            for (int i = 0; i < nColorCount; i++)
            {
                nR += aColor[i].R;
                nG += aColor[i].G;
                nB += aColor[i].B;
            }
            if (nColorCount > 0)
            {
                return Color.FromArgb(nR / nColorCount, nG / nColorCount, nB / nColorCount);
            }
            return Color.Transparent;
        }

        /// <summary>
        /// Returns the sum of RGB: returnvalue = r + g + b
        /// </summary>
        /// <param name="color"></param>
        /// <returns></returns>
        public static int RGBChannelSum(Color color)
        {
            return color.R + color.G + color.B;
        }

        /// <summary>
        /// Checks if all Color components are less than given r,g,b
        /// </summary>
        /// <param name="color"></param>
        /// <param name="r"></param>
        /// <param name="g"></param>
        /// <param name="b"></param>
        /// <returns></returns>
        public static bool IsLess(Color color, int r, int g, int b)
        {
            return color.R < r && color.G < g && color.B < b;
        }

        /// <summary>
        /// Opposite to IsLess
        /// </summary>
        /// <param name="color"></param>
        /// <param name="r"></param>
        /// <param name="g"></param>
        /// <param name="b"></param>
        /// <returns></returns>
        public static bool IsMore(Color color, int r, int g, int b)
        {
            return color.R > r && color.G > g && color.B > b;
        }

        /// <summary>
        /// Same as is more but also boundaries are valid
        /// </summary>
        /// <param name="color"></param>
        /// <param name="r"></param>
        /// <param name="g"></param>
        /// <param name="b"></param>
        /// <returns></returns>
        public static bool IsMoreOrEqual(Color color, int r, int g, int b)
        {
            return color.R >= r && color.G >= g && color.B >= b;
        }

        /// <summary>
        /// Same as is less but also boundaries are valid
        /// </summary>
        /// <param name="color"></param>
        /// <param name="r"></param>
        /// <param name="g"></param>
        /// <param name="b"></param>
        /// <returns></returns>
        public static bool IsLessOrEqual(Color color, int r, int g, int b)
        {
            return color.R <= r && color.G <= g && color.B <= b;
        }

        /// <summary>
        /// returns if one of the Color RGB components is smaller than specified r,g,b
        /// </summary>
        /// <param name="color"></param>
        /// <param name="r"></param>
        /// <param name="g"></param>
        /// <param name="b"></param>
        /// <returns></returns>
        public static bool OneIsLess(Color color, int r, int g, int b)
        {
            return color.R < r || color.G < g || color.B < r;
        }

        /// <summary>
        /// Same as OneIsLess but also boundaries are valid
        /// </summary>
        /// <param name="color"></param>
        /// <param name="r"></param>
        /// <param name="g"></param>
        /// <param name="b"></param>
        /// <returns></returns>
        public static bool OneIsLessOrEqual(Color color, int r, int g, int b)
        {
            return color.R <= r || color.G <= g || color.B <= r;
        }

        /// <summary>
        /// Checks if given Color color is in range of Color(rMin,gMin,bMin) to Color(rMax, gMax, bMax)
        /// </summary>
        /// <param name="color">The color.</param>
        /// <param name="rMin">The r min.</param>
        /// <param name="gMin">The g min.</param>
        /// <param name="bMin">The b min.</param>
        /// <param name="rMax">The r max.</param>
        /// <param name="gMax">The g max.</param>
        /// <param name="bMax">The b max.</param>
        /// <returns>
        /// 	<c>true</c> if [is in range] [the specified color]; otherwise, <c>false</c>.
        /// </returns>
        public static bool IsInRange(Color color, int rMin, int gMin, int bMin, int rMax, int gMax, int bMax)
        {
            return (color.R > rMin && color.R < rMax) && (color.G > gMin && color.G < gMax) && (color.B > bMin && color.B < bMax);
        }

        /// <summary>
        /// Determines whether [is in range inclusive] [the specified color].
        /// </summary>
        /// <param name="color">The color.</param>
        /// <param name="rMin">The r min.</param>
        /// <param name="gMin">The g min.</param>
        /// <param name="bMin">The b min.</param>
        /// <param name="rMax">The r max.</param>
        /// <param name="gMax">The g max.</param>
        /// <param name="bMax">The b max.</param>
        /// <returns>
        /// 	<c>true</c> if [is in range inclusive] [the specified color]; otherwise, <c>false</c>.
        /// </returns>
        public static bool IsInRangeInclusive(Color color, int rMin, int gMin, int bMin, int rMax, int gMax, int bMax)
        {
            return (color.R >= rMin && color.R <= rMax) 
                && (color.G >= gMin && color.G <= gMax) 
                && (color.B >= bMin && color.B <= bMax);
        }

        /// <summary>
        /// Determines whether the specified color is similar.
        /// </summary>
        /// <param name="color">The color.</param>
        /// <param name="nDiff">The n diff.</param>
        /// <returns>
        /// 	<c>true</c> if the specified color is similar; otherwise, <c>false</c>.
        /// </returns>
        public static bool IsSimilar(Color color, int nDiff)
        {
            return Math.Abs(color.R - color.G) <= nDiff && Math.Abs(color.G - color.B) <= nDiff;
        }

        /// <summary>
        /// Returns if one of the components (rgb) is more or equal tolerance
        /// </summary>
        /// <param name="colorFirst"></param>
        /// <param name="colorSecond"></param>
        /// <param name="r"></param>
        /// <param name="g"></param>
        /// <param name="b"></param>
        /// <returns></returns>
        public static bool DifferenceIsMoreOrEqual(Color colorFirst, Color colorSecond, int r, int g, int b)
        {
            return (Math.Abs(colorFirst.R-colorSecond.R)>=r 
                || Math.Abs(colorFirst.G-colorSecond.G)>=g 
                || Math.Abs(colorFirst.B-colorSecond.B)>=b);
        }

        /// <summary>
        /// Checks if the colors are in tolerance.
        /// </summary>
        /// <param name="colorFirst"></param>
        /// <param name="colorNext"></param>
        /// <param name="r"></param>
        /// <param name="g"></param>
        /// <param name="b"></param>
        /// <returns></returns>
        public static bool IsInColorTolerance(Color colorFirst, Color colorNext, int r, int g, int b)
        {
            return Math.Abs(colorFirst.R - colorNext.R) <= r
                && Math.Abs(colorFirst.G - colorNext.G) <= g
                && Math.Abs(colorFirst.B - colorNext.B) <= b;
        }

        /// <summary>
        /// Checks if the Colors are in luminance tolerance.
        /// </summary>
        /// <param name="colorFirst"></param>
        /// <param name="colorNext"></param>
        /// <param name="nLumaTolerance"></param>
        /// <returns></returns>
        public static bool IsInLuminanceTolerance(Color colorFirst, Color colorNext, float nLumaTolerance)
        {
            float nFirstLuminance = GetLuminance(colorFirst);
            float nNextLuminance = GetLuminance(colorNext);
            return Math.Abs(nFirstLuminance - nNextLuminance) <= nLumaTolerance;
        }


        /// <summary>
        /// Checks if colors are in HUE tolerance
        /// </summary>
        /// <param name="colorFirst"></param>
        /// <param name="colorNext"></param>
        /// <param name="nHueTolerance"></param>
        /// <returns></returns>
        public static bool IsInHueTolerance(Color colorFirst, Color colorNext, float nHueTolerance)
        {
            float fFirstHue = colorFirst.GetHue();
            float fNextHue = colorNext.GetHue();
            return Math.Abs(fFirstHue - fNextHue) <= nHueTolerance;
        }

        /// <summary>
        /// Checks if colors are in brightness tolerance
        /// </summary>
        /// <param name="colorFirst"></param>
        /// <param name="colorNext"></param>
        /// <param name="fBrightnessTolerance"></param>
        /// <returns></returns>
        public static bool IsBrightNessTolerance(Color colorFirst, Color colorNext, float fBrightnessTolerance)
        {
            float fFirstHue = colorFirst.GetBrightness();
            float fNextHue = colorNext.GetBrightness();
            return Math.Abs(fFirstHue - fNextHue) <= fBrightnessTolerance;
        }

        /// <summary>
        /// checks if colors are in saturation tolerance
        /// </summary>
        /// <param name="colorFirst"></param>
        /// <param name="colorNext"></param>
        /// <param name="fSaturationTolerance"></param>
        /// <returns></returns>
        public static bool IsInSaturationTolerance(Color colorFirst, Color colorNext, float fSaturationTolerance)
        {
            float fFirstSaturation = colorFirst.GetSaturation();
            float fNextSaturation = colorNext.GetSaturation();
            return Math.Abs(fFirstSaturation - fNextSaturation) <= fSaturationTolerance;
        }

        /// <summary>
        /// Returns a luminance value of a given color
        /// </summary>
        /// <param name="c"></param>
        /// <returns></returns>
        public static float GetLuminance(Color c)
        {
            float fLuma = c.R * 0.3f + c.G * 0.59f + c.B * 0.11f;
            return fLuma;
        }

        /// <summary>
        /// Mixes the colors.
        /// Linear interpolation of ARGB values.
        /// </summary>
        /// <param name="t"> the interpolation parameter</param>
        /// <param name="rgb1">rgb1 the lower interpolation range</param>
        /// <param name="rgb2">rgb2 the upper interpolation range</param>
        /// <returns>the interpolated value</returns>
        public static int MixColors(float t, int rgb1, int rgb2)
        {
            int a1 = (rgb1 >> 24) & 0xff;
            int r1 = (rgb1 >> 16) & 0xff;
            int g1 = (rgb1 >> 8) & 0xff;
            int b1 = rgb1 & 0xff;
            int a2 = (rgb2 >> 24) & 0xff;
            int r2 = (rgb2 >> 16) & 0xff;
            int g2 = (rgb2 >> 8) & 0xff;
            int b2 = rgb2 & 0xff;
            a1 = ImageMath.LinearInterpolate(t, a1, a2);
            r1 = ImageMath.LinearInterpolate(t, r1, r2);
            g1 = ImageMath.LinearInterpolate(t, g1, g2);
            b1 = ImageMath.LinearInterpolate(t, b1, b2);
            return (a1 << 24) | (r1 << 16) | (g1 << 8) | b1;
        }

        /// <summary>
        /// Bilinear interpolation of ARGB values.
        /// </summary>
        /// <param name="x">x the X interpolation parameter 0..1</param>
        /// <param name="y">y the y interpolation parameter 0..1</param>
        /// <param name="nw">rgb array of four ARGB values in the order NW, NE, SW, SE</param>
        /// <param name="ne">rgb array of four ARGB values in the order NW, NE, SW, SE</param>
        /// <param name="sw">rgb array of four ARGB values in the order NW, NE, SW, SE</param>
        /// <param name="se">rgb array of four ARGB values in the order NW, NE, SW, SE</param>
        /// <returns>return the interpolated value</returns>
        public static int BilinearInterpolate(float x, float y, int nw, int ne, int sw, int se)
        {
            float m0, m1;
            int a0 = (nw >> 24) & 0xff;
            int r0 = (nw >> 16) & 0xff;
            int g0 = (nw >> 8) & 0xff;
            int b0 = nw & 0xff;
            int a1 = (ne >> 24) & 0xff;
            int r1 = (ne >> 16) & 0xff;
            int g1 = (ne >> 8) & 0xff;
            int b1 = ne & 0xff;
            int a2 = (sw >> 24) & 0xff;
            int r2 = (sw >> 16) & 0xff;
            int g2 = (sw >> 8) & 0xff;
            int b2 = sw & 0xff;
            int a3 = (se >> 24) & 0xff;
            int r3 = (se >> 16) & 0xff;
            int g3 = (se >> 8) & 0xff;
            int b3 = se & 0xff;

            float cx = 1.0f - x;
            float cy = 1.0f - y;

            m0 = cx * a0 + x * a1;
            m1 = cx * a2 + x * a3;
            int a = (int)(cy * m0 + y * m1);

            m0 = cx * r0 + x * r1;
            m1 = cx * r2 + x * r3;
            int r = (int)(cy * m0 + y * m1);

            m0 = cx * g0 + x * g1;
            m1 = cx * g2 + x * g3;
            int g = (int)(cy * m0 + y * m1);

            m0 = cx * b0 + x * b1;
            m1 = cx * b2 + x * b3;
            int b = (int)(cy * m0 + y * m1);

            return (a << 24) | (r << 16) | (g << 8) | b;
        }

    }
}
